﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.Windows.Media;
using Bling.DSL;
using Bling.WPF;
using Bling.Util;
using Bling.Physics;


namespace Bling.PhysicsTutorial {
  /// <summary>
  /// Simplest physics example. Use physics to create a goo cursor. 
  /// </summary>
  public class GooCursor : PhysicsCanvas {
    public GooCursor() : base("GooCursor", 10) { }
    protected override Action Init(CanvasBl MainCanvas, World World) {
      MainCanvas.Background = Brushes.White;
      // Base size, can tweek via scale.
      PointBl InitSize = new PointBl(50, 50);
      // create a cursor with 100 circles.
      int Count = 100;
      // Control scaling
      LabelSliderBl Scale = new LabelSliderBl(MainCanvas) {
        LeftTop = new PointBl(0,0), 
        ZIndex = 2, Slider = {
          Minimum = .1, Maximum = 3d, Value = 1d,
        },
        WidthRatio = .13, LabelName = "Scale",
      };
      // Control stiffness of trail, 0 means no stiffness, the circles will just stay in place.
      LabelSliderBl Stiff = new LabelSliderBl(MainCanvas) {
        LeftTop = Scale.LeftBottom,
        ZIndex = 2, Slider = {
          Minimum = 0, Maximum = 1d, Value = .5d,
        },
        WidthRatio = .13, LabelName = "Stiff",
      };
      // control whether the cursor is black or multi-colored.
      CheckBoxBl SimpleColor = new CheckBoxBl(MainCanvas) {
        ZIndex = 2, LeftTop = Stiff.LeftBottom, Content = "Black",
        IsChecked = true,
        Font = Stiff.Label.Font, 
      };
      // Create a block of Count circles. 

      PositionBlock<Ellipse, EllipseBl> block = new PositionBlock<Ellipse, EllipseBl>(World, Count, index => {
        // factory method to create each circle.
        return new EllipseBl(MainCanvas) {
          Fill = // fill is black if simple color is checked, otherwise more complicated
            SimpleColor.IsChecked.Condition(Brushes.Black, 
            new SolidColorBrushBl() { Color = index.SelectColor(), Opacity = 0.9 }), 
          // size of circle based in init size, scale, and index (the circles get smaller as index increases).  
          Size = InitSize * Scale * (Count - index) / (Count),
          Stroke = { Brush = Brushes.Transparent }, 
          // don't bother hit testing.
          IsHitTestVisible = false, 
        };
      }) { Name = "CursorPoints", };

      // An invisible thumb acts to hold the current mouse position. 
      ThumbBl thumb = new ThumbBl(MainCanvas) {
        CenterPosition = MainCanvas.CenterSize, ZIndex = 2, Visibility = false,
      };
      // block.ForAll allows us to constraint body properties efficiently.
      block.ForAll(body => {
        // relax 3 times so that changes propagate through the tail more evenly.
        for (int i = 0; i < 3; i++) {
          // Only relax, for first circle, just relax to the position of the thumb
          // for other circles, relax according to the previous circle, with a strength related to the stiffness slider.
          body.Position().Relax[(body.Index == 0).Condition(1, Stiff)] =
            (body.Index == 0).Condition(thumb.CenterPosition, body.Prev[1].Position());
        }
        // link physical position to UI body's UI position, otherwise the physical position won't influence rendering.
        body.Position().Link.To = body.At.CenterPosition;
      });
      return () => {
        // Update the thumb's position when the mouse moves on the canvas, use an assign
        // action to make this more effectient.
        Action UpdateMouse = PointBl.Assign(thumb.CenterPosition, MainCanvas.MousePosition);
        MainCanvas.OnMouseMove = (x, y) => {
          UpdateMouse();
          return true;
        };

      };
    }
  }
}
